﻿using Digitalmes.ActionFilters;

using Digitalmes.Extensions;
using Digitalmes.Hubs;
using Digitalmes.Middlewares;
using Digitalmes.Model.ThirdParty.FdsWeber;
using Digitalmes.Services.Hosted;
using Digitalmes.Signals;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.SpaServices;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using MQTTnet.AspNetCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using VueCliMiddleware;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Core.Support.FileHandlers;
using WalkingTec.Mvvm.Mvc;

namespace Digitalmes
{
    public class Startup
    {
        public IConfiguration ConfigRoot { get; }

        public Startup(IWebHostEnvironment env, IConfiguration config)
        {
            AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
            ConfigRoot = config;
        }


        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOptions();
            services.AddMemoryCache(); // 注册IMemoryCache
            services.AddWtmWorkflow(ConfigRoot);
            services.AddDistributedMemoryCache();
            services.AddWtmSession(3600, ConfigRoot);
            services.AddWtmCrossDomain(ConfigRoot);
            services.AddWtmAuthentication(ConfigRoot);
            services.AddWtmHttpClient(ConfigRoot);
            services.AddWtmSwagger(true);
            services.AddWtmMultiLanguages(ConfigRoot);

            services.AddMvc(options =>
            {
                options.Filters.Add<UnitOfWorkFilter>();
                options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
                options.UseWtmMvcOptions();
            })
            .AddJsonOptions(options => {
                options.UseWtmJsonOptions();
                options.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.Strict;
            })
            
            .ConfigureApiBehaviorOptions(options =>
            {
                options.UseWtmApiOptions();
            })
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .AddWtmDataAnnotationsLocalization(typeof(Program));

            

            services.AddWtmContext(ConfigRoot, (options) => {
                options.DataPrivileges = DataPrivilegeSettings();
                options.CsSelector = CSSelector;
                options.FileSubDirSelector = SubDirSelector;
                options.ReloadUserFunc = ReloadUser;
            });

            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "wwwroot";
            });

            services.AddWtmMediatR();
            services.AddMesService(ConfigRoot);
            services.AddDbContextFactory(ConfigRoot);

            services.AddSignalR();

            services.AddWcfService();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IOptionsMonitor<Configs> configs, IHostEnvironment env,MqttController mqtt)
        {
            app.UseMiddleware<TenantMiddleware>();

            app.UseExceptionHandler(configs.CurrentValue.ErrorHandler);
            DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();
            defaultFilesOptions.DefaultFileNames.Clear();
            defaultFilesOptions.DefaultFileNames.Add("index.html");
            app.UseDefaultFiles(defaultFilesOptions);
            app.UseStaticFiles();
            app.UseWtmStaticFiles();
            app.UseSpaStaticFiles();
            app.UseWtmSwagger();
            app.UseRouting();
            app.UseWtmMultiLanguages();
            app.UseWtmCrossDomain();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseSession();
            app.UseWtm();
            // 配置WebSocket支持
            app.UseWebSockets();
            app.UseWcfService();

            app.UseEndpoints(endpoints =>
            {
                // 添加MQTT端点
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapConnectionHandler<MqttConnectionHandler>(
                        "/mqtt",
                        httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
                            protocolList => protocolList.FirstOrDefault() ?? string.Empty);
                });
                endpoints.MapHub<ChatHub>("/chatHub");
                endpoints.MapControllerRoute(
                   name: "areaRoute",
                   pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapFallbackToFile(env.IsDevelopment() ? "index_dev.html" : "");
            });



            app.UseMqttServer(
                server =>
                {
                    /*
                     * Attach event handlers etc. if required.
                     */

                    server.ValidatingConnectionAsync += mqtt.ValidateConnection;
                    server.ClientConnectedAsync += mqtt.HandleClientConnected;
                    server.ClientDisconnectedAsync += mqtt.HandleClientDisconnected;
                    server.InterceptingSubscriptionAsync += mqtt.ValidateSubscription;
                    server.InterceptingPublishAsync += mqtt.InterceptApplicationMessage;
                   
                });


            app.UseWtmContext();



            //多库读写方案
            //var factory = app.ApplicationServices.CreateScope().ServiceProvider.GetRequiredService<IDbContextFactory>();
            //var mom = factory.CreateDbContext("FdsWeber");
            //var lst = mom?.Set<Results>().Take(100).ToList();

            //MediatR
            //var mr = app.ApplicationServices.CreateScope().ServiceProvider.GetRequiredService<IMediator>();
            //var result= mr.Send(new EntrySignal());

        }

        /// <summary>
        /// Wtm will call this function to dynamiclly set connection string
        /// 框架会调用这个函数来动态设定每次访问需要链接的数据库
        /// </summary>
        /// <param name="context">ActionContext</param>
        /// <returns>Connection string key name</returns>
        public string CSSelector(ActionExecutingContext context)
        {
            //To override the default logic of choosing connection string,
            //change this function to return different connection string key
            //根据context返回不同的连接字符串的名称
            return null;
        }

        /// <summary>
        /// Set data privileges that system supports
        /// 设置系统支持的数据权限
        /// </summary>
        /// <returns>data privileges list</returns>
        public List<IDataPrivilege> DataPrivilegeSettings()
        {
            List<IDataPrivilege> pris = new List<IDataPrivilege>();
            //Add data privilege to specific type
            //指定哪些模型需要数据权限
            
            return pris;
        }

        /// <summary>
        /// Set sub directory of uploaded files
        /// 动态设置上传文件的子目录
        /// </summary>
        /// <param name="fh">IWtmFileHandler</param>
        /// <returns>subdir name</returns>
        public string SubDirSelector(IWtmFileHandler fh)
        {
            return null;
        }

        /// <summary>
        /// Custom Reload user process when cache is not available
        /// 设置自定义的方法重新读取用户信息，这个方法会在用户缓存失效的时候调用
        /// </summary>
        /// <param name="context"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public LoginUserInfo ReloadUser(WTMContext context, string account)
        {
            return null;
        }
    }
}

